一、元件(Conpoment)與槽(slot)
- Laravel 5.4 版本後加入
- 提供另一種納入內的方法
- 基本用法 @component 指令與 $slot 變數
<!-- detail_modal.blade.php -->
<div class="modal">
<div>
{{ $slot }}
</div>
<div>加入購物車</div>
</div>
<!-- 在其他模板中引入 -->
<!-- product_list.blade.php -->
@foreach ( $products as $product )
@component('product.detail_modal')
商品詳細內容
@endcomponent
@endforeah
- 多個插槽
- 使用 @slot 指定非預設插槽內容
- 其餘部分會放入預設插槽
<!-- detail_modal.blade.php -->
<div class="modal">
<h2>{{ $title }}</h2>
<div>
{{ $slot }}
</div>
<div>加入購物車</div>
</div>
<!-- product_list.blade.php -->
@foreach ( $products as $product )
@component('product.detail_modal')
@slot('title')
這是商品名稱
@endslot
<p>商品詳細內容</p>
@endcomponent
@endforeah
<!-- 若有要傳入的參數是陣列或物件, 可在第二個參數設定 -->
@foreach ( $products as $product )
@component('product.detail_modal', ['coupons', $product->$coupons])
@slot('title')
這是商品名稱
@endslot
<p>商品詳細內容</p>
@endcomponent
@endforeah
二、將元件更名為指令
* e.g. @component('product.detail_modal') -> @detail_modal
* 可以使用 Blade::component() 靜態方法,常在 AppServiceProvider 的 boot() 方法執行
```php
# 第一個參數為模板位置, 第二個參數是要產生的指令名稱
Blade::component('product.detail_modal', 'myProductDetail')
# 使用
@myProductDetail
# 內容...
@endmyProductDetail
```
三、 view Composer 與服務注入
- 定義當使用到特定 view 時, 必須載入相關使用到的資料, e.g. 導覽列載入設定好的項目
- 避免每個 route() 或 redirect() 時都必須 with(), 手動添加資料
- 使用全域共用變數
# 在服務供應器 boot() 方法內設定
public function boot() {
# 設定 mainMenu 變數抓取主導覽內容
view()->share('mainMenu', Menu::get('main'));
}
# 單一模板綁定
view()->composer('component.menu', function($view){
$view->with('mainMenu', Menu::get('main'));
});
# 多模板綁定
view()->composer(['component.menu', 'component.footer_menu'], function($view){
$view->with('mainMenu', Menu::get('main'));
});
# 以 * 綁定多模板
view()->composer('component.*', function($view){
$view->with('mainMenu', Menu::get('main'));
});
# 建立 Class, 建議位置在 App\Http\ViewComposer
namespace App\Http\ViewComposers;
use App\Models\Menu;
use Illuminate\Contracts\View\View;
Class MenuComposer{
public function compose(View $view) {
$view->with('mainMenu', Menu::get('main'));
}
}
# 設定在服務提供內
# 與 Closure 用法類似, 只是要傳遞一個 Class 給方法
public function boot(){
view()->composer(
'component.menu',
\App\Http\ViewComposer\MenuComposer::class
);
}
四、Blade 服務注入
Route::get('product/list', function( ProductCollection $products ) {
return view('product.list')->with('products', $products);
});
@inject('products', 'App\Services\Products');
<div>
總筆數: {{ $products->count }}
</div>
自訂 Blade 指令
# 通常會寫在 boot 內
public function boot(){
Blade::directive('ifProduct', function(){
# 回傳一個 PHP 字串
return "<?php if ( product()->getCount() ): ?>";
# Blade 指令會產生快取, 不要用固定值回傳
# $productCnt = product()->geteCount();
# 這樣會造成回傳可能是快取的結果, 不是即時更新
# return "<?php if ( $productCnt ) : ?>";
});
}
# 帶入參數
public function boot(){
Blade::directive('ifProduct', function($category_id){
# 回傳一個 PHP 字串
return "<?php if ( product($category_id)->getCount() ): ?>";
});
}
# 簡化自訂 if 指令
public function boot(){
Blade::if('ifProduct', function($category_id){
# 回傳一個 PHP 字串
return product($category_id)->getCount() > 0;
});
}